﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using FluentDml.Tests.TestClasses;
using NHibernate.Linq;
using NUnit.Framework;

namespace FluentDml.Tests
{
    [TestFixture]
    public class WhereClauseTests
    {
        private static InMemoryDatabase _db;

        [TestFixtureSetUp]
        public void FixtureSetup()
        {
            _db = new InMemoryDatabase();
        }

        [TestFixtureTearDown]
        public void FixtureTearDown()
        {
            _db.Dispose();
        }

        [SetUp]
        public void Setup()
        {
            _db.CreateSession();

            IList<Person> persons = TestData.GenerateSession<Person>().List<Person>(100).Get();
            IList<Address> addresses = TestData.GenerateSession<Address>().List<Address>(100)
                .Random(50)
                    .Impose(x => x.City, "Oxford")
                    .Impose(x => x.PostCode, "OX01 1TY")
                .Next(25)
                    .Impose(x => x.City, "London")
                    .Impose(x => x.PostCode, "LN01 1TY")
                .Next(25)
                    .Impose(x => x.City, "Northampton")
                    .Impose(x => x.PostCode, "NN01 1AB")
                .All()
                .Random(50)
                    .Impose(x => x.Street, "Main St")
                .Next(25)
                    .Impose(x => x.Street, "Church St")
                .Next(25)
                    .Impose(x => x.Street, "Walnut Cl")
                .All().Get();


            for (int i = 0; i < 100; i++)
            {
                Person person = persons[i];
                person.Address = addresses[i];
                _db.Session.Save(person);
            }   
                
            IList<LogEntry> logs = TestData.GenerateSession<LogEntry>().List<LogEntry>(100)
                .Random(25)
                    .Impose(x => x.Level, "Debug")
                .Next(25)
                    .Impose(x => x.Level, "Error")
                .Next(50)
                    .Impose(x => x.Level, "Info")
                .All()
                .Random(10)
                    .Impose(x=>x.DateTime, DateTime.Now)
                .All().Get();

            foreach (var log in logs)
            {
                _db.Session.Save(log);
            }

            _db.Session.Flush();
        }

        [TearDown]
        public void TearDown()
        {
            _db.TearDownSession();
        }

        [Test]
        public void Where_Logs_Date_Are_Greater_Than_Using_AddHours_To_Calculate_The_Comparison()
        {
            Expression<Func<LogEntry, bool>> where = x => x.DateTime > DateTime.Now.AddHours(-1);
            int count = _db.Session.Query<LogEntry>().Where(where).Count();

            string generateCommand = _db.Session.Delete<LogEntry>(where).GenerateCommand();

            int executeCommand = _db.Session.Delete<LogEntry>(where).ExecuteCommand();

            Assert.AreEqual(count, executeCommand);
        }

        [Test]
        public void Where_Logs_Date_Are_Greater_Than()
        {
            DateTime dateTime = DateTime.Now.AddHours(-1);
            Expression<Func<LogEntry, bool>> where = x => x.DateTime > dateTime;
            int count = _db.Session.Query<LogEntry>().Where(where).Count();

            string generateCommand = _db.Session.Delete<LogEntry>(where).GenerateCommand();

            int executeCommand = _db.Session.Delete<LogEntry>(where).ExecuteCommand();

            Assert.AreEqual(count, executeCommand);
        }

        [Test]
        public void Where_Logs_Id_Is_Greater_Than()
        {
            Expression<Func<LogEntry, bool>> where = x => x.Id > 30;
            int count = _db.Session.Query<LogEntry>().Where(where).Count();

            string generateCommand = _db.Session.Delete<LogEntry>(where).GenerateCommand();

            int executeCommand = _db.Session.Delete<LogEntry>(where).ExecuteCommand();

            Assert.AreEqual(count, executeCommand);
        }

        [Test]
        public void Where_Logs_Id_Is_Greater_Than_Using_A_Local_Variable()
        {
            int id = 30;
            Expression<Func<LogEntry, bool>> where = x => x.Id > id;
            int count = _db.Session.Query<LogEntry>().Where(where).Count();

            string generateCommand = _db.Session.Delete<LogEntry>(where).GenerateCommand();

            int executeCommand = _db.Session.Delete<LogEntry>(where).ExecuteCommand();

            Assert.AreEqual(count, executeCommand);
        }

        [Test]
        public void Where_Person_Address_City_Equals_Oxford()
        {
            Expression<Func<Person, bool>> where = x => x.Address.City == "Oxford";
            int count = _db.Session.Query<Person>().Where(where).Count();

            string generateCommand = _db.Session.Delete<Person>(where).GenerateCommand();

            int executeCommand = _db.Session.Delete<Person>(where).ExecuteCommand();

            Assert.AreEqual(count, executeCommand);
        }

        [Test]
        public void Where_Person_Name_Equals_James()
        {
            Expression<Func<Person, bool>> where = x => x.FirstName == "James";
            int count = _db.Session.Query<Person>().Where(where).Count();

            string generateCommand = _db.Session.Delete<Person>(where).GenerateCommand();

            int executeCommand = _db.Session.Delete<Person>(where).ExecuteCommand();

            Assert.AreEqual(count, executeCommand);
        }


        [Test]
        public void Where_Person_Address_City_Equals_Oxford_Using_Update()
        {
            Expression<Func<Person, bool>> where = x => x.Address.City == "Oxford";
            int count = _db.Session.Query<Person>().Where(where).Count();

            string generateCommand = _db.Session.Update<Person>(where)
                .Set(x=>x.FirstName, "Bob")
                .GenerateCommand();

            int executeCommand = _db.Session.Update<Person>(where)
                .Set(x=>x.FirstName, "Bob")
                .ExecuteCommand();

            Assert.AreEqual(count, executeCommand);
        }

        [Test]
        public void Where_Person_Address_City_Not_Equal_Oxford()
        {
            Expression<Func<Person, bool>> where = x => x.Address.City != "Oxford";
            int count = _db.Session.Query<Person>().Where(where).Count();

            string generateCommand = _db.Session.Delete<Person>(where)
                .GenerateCommand();

            int executeCommand = _db.Session.Delete<Person>(where)
                .ExecuteCommand();

            Assert.AreEqual(count, executeCommand);
        }


        [Test]
        public void Where_Not_Person_Address_City_Equals_Oxford()
        {
            Expression<Func<Person, bool>> where = x => !(x.Address.City == "Oxford");
            int count = _db.Session.Query<Person>().Where(where).Count();

            string generateCommand = _db.Session.Delete<Person>(where)
                .GenerateCommand();

            int executeCommand = _db.Session.Delete<Person>(where)
                .ExecuteCommand();

            Assert.AreEqual(count, executeCommand);
        }

    }
}
